﻿using DataProcess.Error;
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace DataProcess
{
    namespace Encryption
    {

        public class RC4Encryption
        {
            static byte[] RC4Init(byte[] key)
            {
                byte[] sbox = new byte[256];
                byte[] k = new byte[256];
                byte tmp = 0;
                for (int i = 0; i <= 255; i++)
                {
                    sbox[i] = (byte)i;
                    k[i] = key[i % key.Length];
                }
                int j = 0;
                for (int i = 0; i <= 255; i++)
                {
                    j = (j + sbox[i] + k[i]) % 256;
                    tmp = sbox[i];
                    sbox[i] = sbox[j];
                    sbox[j] = tmp;
                }
                return sbox;
            }
            static void RC4(Stream data, byte[] key, Stream output)
            {
                key = RC4Init(key);

                for (long i = 0; i < data.Length; i++)
                {
                    byte r = (byte)(key[i % 256] ^ data.ReadByte());
                    output.WriteByte(r);
                }
            }
            static byte[] RC4(byte[] data, byte[] key)
            {
                byte[] result;
                using (MemoryStream ms = new MemoryStream(data))
                {
                    using (MemoryStream output = new MemoryStream())
                    {
                        RC4(ms, key, output);
                        result = output.ToArray();
                    }
                }
                return result;
            }
            /// <summary>
            /// RC4加密（原始）
            /// </summary>
            /// <param name="text">加密文本</param>
            /// <param name="key">密钥</param>
            /// <param name="encoding">编码格式</param>
            /// <returns></returns>
            public static byte[] RC4Encrypt(string text, string key, Encoding encoding)
            {
                return RC4(encoding.GetBytes(text), encoding.GetBytes(key));
            }
            /// <summary>
            /// RC4加密（直接byte转char）
            /// </summary>
            /// <param name="text">加密文本</param>
            /// <param name="key">密钥</param>
            /// <param name="encoding">编码格式</param>
            /// <returns></returns>
            public static string RC4Encrypt_RawString(string text, string key, Encoding encoding)
            {
                return encoding.GetString(RC4Encrypt(text, key, encoding));
            }
            /// <summary>
            /// RC4加密（Base64）
            /// </summary>
            /// <param name="text">加密内容</param>
            /// <param name="key">密钥</param>
            /// <param name="encoding">编码格式</param>
            /// <returns></returns>
            public static string RC4Encrypt_Base64(string text, string key, Encoding encoding)
            {
                return Convert.ToBase64String(RC4(encoding.GetBytes(text), encoding.GetBytes(key)));
            }
            /// <summary>
            /// RC4解密（Base64）
            /// </summary>
            /// <param name="text">加密内容</param>
            /// <param name="key">密钥</param>
            /// <param name="encoding">编码格式</param>
            /// <returns></returns>
            public static string RC4Decrypt_Base64(string text, string key, Encoding encoding)
            {
                return encoding.GetString(RC4(Convert.FromBase64String(text), encoding.GetBytes(key)));
            }
            /// <summary>
            /// RC4加密（流）
            /// </summary>
            /// <param name="content">加密内容</param>
            /// <param name="key">密钥</param>
            /// <param name="output">输出流</param>
            public static void RC4Encrypt(Stream content, byte[] key, Stream output)
            {
                RC4(content, key, output);
            }
            /// <summary>
            /// RC4加密（流）
            /// </summary>
            /// <param name="content">加密内容</param>
            /// <param name="key">密钥</param>
            /// <param name="output">输出流</param>
            /// <param name="encoding">密钥编码格式</param>
            public static void RC4Encrypt(Stream content, string key, Stream output, Encoding encoding)
            {
                RC4(content, encoding.GetBytes(key), output);
            }

        }

        /// <summary>
        /// MD5加密器
        /// </summary>
        public class MD5Coder
        {
            /// <summary>
            /// 生成MD5码
            /// </summary>
            /// <param name="encoding">编码方式</param>
            /// <param name="text">需要生成MD5码的字符串</param>
            /// <returns></returns>
            public static string MD5Encrypt(string text, Encoding encoding)
            {
                using (MemoryStream ms = new MemoryStream(encoding.GetBytes(text)))
                {
                    return MD5Coder.MD5Encrypt(ms);
                }
            }
            /// <summary>
            /// 使用流生成MD5.(可以为大文件生成MD5)
            /// </summary>
            /// <param name="stream">需要处理的流</param>
            /// <returns></returns>
            public static string MD5Encrypt(Stream stream)
            {
                MD5 d5 = new MD5CryptoServiceProvider();
                string res = "";
                foreach (byte c in d5.ComputeHash(stream))
                {
                    string x = DataProcess.Mathematics.NumberCase.ExchangeFromTen(c, 16);
                    x = x.PadLeft(2, '0');
                    res += x;
                }
                return res;
            }
            /// <summary>
            /// 进行MD5加密并以Byte数组的形式得到
            /// </summary>
            /// <param name="stream"></param>
            /// <returns></returns>
            public static byte[] MD5EncryptToBytes(Stream stream)
            {
                MD5 d5 = new MD5CryptoServiceProvider();
                return d5.ComputeHash(stream);
            }
        }

        /// <summary>
        /// HMAC加密器
        /// </summary>
        public class HMACMaker
        {
            /// <summary>
            /// 加密类别
            /// </summary>
            public enum Level
            {
                SHA1, SHA256, SHA384, SHA512, MD5
            }
            /// <summary>
            /// 获取HMAC加密实体
            /// </summary>
            /// <param name="level"></param>
            /// <returns></returns>
            private static HMAC GetHMAC(Level level)
            {
                switch (level)
                {
                    case Level.MD5:
                        return new HMACMD5();
                    case Level.SHA1:
                        return new HMACSHA1();
                    case Level.SHA256:
                        return new HMACSHA256();
                    case Level.SHA384:
                        return new HMACSHA384();
                    case Level.SHA512:
                        return new HMACSHA512();
                    default:
                        return null;
                }
            }
            public static byte[] HMAC(byte[] key, byte[] value, Level level = Level.SHA1)
            {
                HMAC doer = GetHMAC(level);
                doer.Key = key;
                return doer.ComputeHash(value);
            }
        }

        /// <summary>
        /// 基础加密类
        /// </summary>
        public class BaseEncryption
        {
            /// <summary>
            /// 加密
            /// </summary>
            /// <param name="content">需要加密的文本</param>
            /// <param name="key">加密密钥</param>
            /// <returns></returns>
            public static string Encrypt(string content, string key)
            {
                List<byte> Tkey;
                List<byte> Tcontent;
                Tkey = new List<byte>(Encoding.Default.GetBytes(key));
                Tcontent = new List<byte>(Encoding.Default.GetBytes(content));
                byte[] keynum = Tkey.ToArray();
                byte[] contentnum = Tcontent.ToArray();
                byte[] result = new byte[contentnum.Length];
                int z = 0;
                string houzhui = "";
                for (int i = 0; i < contentnum.Length; i++)
                {
                    if (z >= keynum.Length)
                    {
                        z = 0;
                    }
                    result[i] = byte.Parse((contentnum[i] % keynum[z]).ToString());
                    houzhui += contentnum[i] / keynum[z];
                    z++;
                }
                return Convert.ToBase64String(result) + " " + houzhui;
            }
            /// <summary>
            /// 解密
            /// </summary>
            /// <param name="Encode">需要解密的字符串</param>
            /// <param name="key">密钥</param>
            /// <returns></returns>
            public static string Decrypt(string Encode, string key)
            {
                if (key.Length == 0)
                {
                    throw new EncryptionError("加密的密钥不能为空！");
                }

                List<byte> Tchushu;
                string[] temp = Encode.Split(new char[] { ' ' });
                Tchushu = new List<byte>(Encoding.Default.GetBytes(key));
                byte[] chushu = Tchushu.ToArray();
                char[] shang = temp[1].ToCharArray();
                int[] S = new int[shang.Length];
                for (int i = 0; i < shang.Length; i++)
                {
                    if (!int.TryParse(shang[i].ToString(), out S[i]))
                    {
                        throw new EncryptionError("读取密码错误");
                    }
                }
                byte[] Ynum = Convert.FromBase64String(temp[0]);
                byte[] beichushu = new byte[shang.Length];
                int z = 0;
                for (int i = 0; i < shang.Length; i++)
                {
                    if (z >= chushu.Length)
                    {
                        z = 0;
                    }
                    if (!byte.TryParse((S[i] * chushu[z] + Ynum[i]).ToString(), out beichushu[i]))
                    {
                        throw new EncryptionError("转换字符错误");
                    }
                    z++;
                }
                string res = Encoding.Default.GetString(beichushu);
                return res;
            }
            /// <summary>
            /// 解密
            /// </summary>
            /// <param name="Encode">需要解密的字符串</param>
            /// <param name="key">密钥</param>
            /// <param name="encode">编码类型</param>
            /// <returns></returns>
            public virtual string Decrypt(string Encode, string key, Encoding encode)
            {
                List<byte> Tchushu;
                string[] temp = Encode.Split(new char[] { ' ' });
                Tchushu = new List<byte>(encode.GetBytes(key));
                byte[] chushu = Tchushu.ToArray();
                char[] shang = temp[1].ToCharArray();
                int[] S = new int[shang.Length];
                for (int i = 0; i < shang.Length; i++)
                {
                    if (!int.TryParse(shang[i].ToString(), out S[i]))
                    {
                        throw new EncryptionError("读取密码错误");
                    }
                }
                byte[] Ynum = Convert.FromBase64String(temp[0]);
                byte[] beichushu = new byte[shang.Length];
                int z = 0;
                for (int i = 0; i < shang.Length; i++)
                {
                    if (z >= chushu.Length)
                    {
                        z = 0;
                    }
                    if (!byte.TryParse((S[i] * chushu[z] + Ynum[i]).ToString(), out beichushu[i]))
                    {
                        throw new EncryptionError("转换字符错误");
                    }
                    z++;
                }
                return encode.GetString(beichushu); ;
            }
            /// <summary>
            /// 解密
            /// </summary>
            /// <param name="content">需要解密的流</param>
            /// <param name="key"></param>
            /// <param name="encode"></param>
            /// <returns></returns>
            public virtual string Decrypt(Stream content, string key, Encoding encode)
            {
                List<byte> Tchushu;
                StreamReader reader = new StreamReader(content);
                string Encode = reader.ReadToEnd();
                reader.Dispose();
                string[] temp = Encode.Split(new char[] { ' ' });
                Tchushu = new List<byte>(encode.GetBytes(key));
                byte[] chushu = Tchushu.ToArray();
                char[] shang = temp[1].ToCharArray();
                int[] S = new int[shang.Length];
                for (int i = 0; i < shang.Length; i++)
                {
                    if (!int.TryParse(shang[i].ToString(), out S[i]))
                    {
                        throw new EncryptionError("读取密码错误");
                    }
                }
                byte[] Ynum = Convert.FromBase64String(temp[0]);
                byte[] beichushu = new byte[shang.Length];
                int z = 0;
                for (int i = 0; i < shang.Length; i++)
                {
                    if (z >= chushu.Length)
                    {
                        z = 0;
                    }
                    if (!byte.TryParse((S[i] * chushu[z] + Ynum[i]).ToString(), out beichushu[i]))
                    {
                        throw new EncryptionError("转换字符错误");
                    }
                    z++;
                }
                string res = encode.GetString(beichushu);
                return res;
            }
            /// <summary>
            /// 加密
            /// </summary>
            /// <param name="content">需要加密的字符串</param>
            /// <param name="key">密钥</param>
            /// <param name="encode">编码类型</param>
            /// <returns></returns>
            public virtual string Encrypt(string content, string key, Encoding encode)
            {

                List<byte> Tkey;
                List<byte> Tcontent;
                Tkey = new List<byte>(encode.GetBytes(key));
                Tcontent = new List<byte>(encode.GetBytes(content));
                byte[] keynum = Tkey.ToArray();
                byte[] contentnum = Tcontent.ToArray();
                byte[] result = new byte[contentnum.Length];
                int z = 0;
                string houzhui = "";
                for (int i = 0; i < contentnum.Length; i++)
                {
                    if (z >= keynum.Length)
                    {
                        z = 0;
                    }
                    result[i] = byte.Parse((contentnum[i] % keynum[z]).ToString());
                    houzhui += contentnum[i] / keynum[z];
                    z++;
                }
                return Convert.ToBase64String(result) + " " + houzhui;
            }
            /// <summary>
            /// 加密
            /// </summary>
            /// <param name="contents">需要加密的流</param>
            /// <param name="key">密钥</param>
            /// <param name="encode">编码类型</param>
            /// <returns></returns>
            public virtual string Encrypt(Stream contents, string key, Encoding encode)
            {

                List<byte> Tkey;
                List<byte> Tcontent;
                StreamReader reader = new StreamReader(contents);
                string content = reader.ReadToEnd();
                Tkey = new List<byte>(encode.GetBytes(key));
                Tcontent = new List<byte>(encode.GetBytes(content));
                byte[] keynum = Tkey.ToArray();
                byte[] contentnum = Tcontent.ToArray();
                byte[] result = new byte[contentnum.Length];
                int z = 0;
                string houzhui = "";
                for (int i = 0; i < contentnum.Length; i++)
                {
                    if (z >= keynum.Length)
                    {
                        z = 0;
                    }
                    result[i] = byte.Parse((contentnum[i] % keynum[z]).ToString());
                    houzhui += contentnum[i] / keynum[z];
                    z++;
                }
                return Convert.ToBase64String(result) + " " + houzhui;
            }

            internal bool isint(char h)
            {
                return h <= 57 && h >= 48;
            }

        }
        /// <summary>
        /// 自制加密算法
        /// </summary>
        public class Encryption : BaseEncryption
        {
            internal string Decode(string x)
            {
                string r = "";
                char[] h = x.ToCharArray();
                for (int i = 0; i < h.Length - 1; i++)
                {
                    if (isint(h[i]) == true)
                    {
                        if (isint(h[i + 1]) == true)
                        {
                            r += h[i];
                        }
                        else
                        {
                            for (int j = 0; j < (h[i + 1] - 65); j++)
                            {
                                r += h[i];
                            }
                        }
                    }
                }
                return r;
            }
            internal string Recode(string x)
            {

                char[] h = x.ToCharArray();
                List<int> num = new List<int>();
                List<int> resnum = new List<int>();
                int nums = 0;
                int j = 0;
                for (int i = 0; j < h.Length;)
                {
                    for (j = i; j < h.Length; j++)
                    {
                        if (h[i] == h[j])
                        {
                            nums++;
                        }
                        if (j >= h.Length)
                        {
                            break;
                        }

                        if (h[i] != h[j])
                        {
                            num.Add(nums);
                            resnum.Add(h[i]);
                            nums = 0;
                            i = j;
                            break;
                        }
                    }
                }
                char t;
                string final = "";
                for (int i = 0; i < num.Count; i++)
                {
                    if (num[i] > 1)
                    {
                        t = (char)(65 + num[i]);
                        final += (char)resnum[i] + t.ToString();
                    }
                    else
                    {
                        final += (char)resnum[i];
                    }
                }
                t = (char)(65 + nums);
                final += h[h.Length - 1] + t.ToString(); ;
                return final;
            }

            /// <summary>
            /// 进阶版加密（缩短了加密后的字符串长度）
            /// </summary>
            /// <param name="content">需要加密的内容</param>
            /// <param name="key">解锁密钥</param>
            /// <returns></returns>
            public string AdvancedEncrypt(string content, string key, Encoding encoding)
            {
                int num = 2;
                byte[] keynum = encoding.GetBytes(key);
                byte[] contentnum = encoding.GetBytes(content);
                List<byte[]> ContentN = new List<byte[]>();
                int partC = contentnum.Length / num;
                byte[] result = new byte[contentnum.Length];
                string[] houzhui = new string[2];
                int z = 0;
                for (int j = 0; j < partC; j++)
                {
                    if (z >= keynum.Length)
                    {
                        z = 0;
                    }
                    result[j] = byte.Parse((contentnum[j] % keynum[z]).ToString());
                    houzhui[0] += contentnum[j] / keynum[z];
                    z++;
                }
                int z1 = partC % key.Length;
                for (int j = partC; j < contentnum.Length; j++)
                {
                    if (z1 >= keynum.Length)
                    {
                        z1 = 0;
                    }
                    result[j] = byte.Parse((contentnum[j] % keynum[z1]).ToString());
                    houzhui[1] += contentnum[j] / keynum[z1];
                    z1++;
                }
                string res = Convert.ToBase64String(result);
                string hou = Recode(houzhui[0] + houzhui[1]);
                return res + " " + hou;
            }
            /// <summary>
            /// 进阶版解密（缩短了加密后的字符串长度）
            /// </summary>
            /// <param name="Encode">密文</param>
            /// <param name="key">解锁密钥</param>
            /// <returns></returns>
            public string AdvancedDecrypt(string Encode, string key, Encoding encoding)
            {
                string[] temp = Encode.Split(new char[] { ' ' });
                byte[] chushu = encoding.GetBytes(key);
                char[] shang = Decode(temp[1]).ToCharArray();
                int[] S = new int[shang.Length];
                for (int i = 0; i < shang.Length; i++)
                {
                    S[i] = int.Parse(shang[i].ToString());
                }
                byte[] Ynum = Convert.FromBase64String(temp[0]);
                byte[] beichushu = new byte[shang.Length];
                int partC = shang.Length / 2;

                int z = 0;
                for (int i = 0; i < partC; i++)
                {
                    if (z >= chushu.Length)
                    {
                        z = 0;
                    }
                    beichushu[i] = byte.Parse((S[i] * chushu[z] + Ynum[i]).ToString());
                    z++;
                }
                int z1 = partC % chushu.Length;
                for (int j = partC; j < shang.Length; j++)
                {
                    if (z1 >= chushu.Length)
                    {
                        z1 = 0;
                    }
                    beichushu[j] = byte.Parse((S[j] * chushu[z1] + Ynum[j]).ToString());
                    z1++;
                }
                return encoding.GetString(beichushu);
            }
        }
    }
}
